#ifndef __FIBER_UTIL_H__
#define __FIBER_UTIL_H__

// 包含必要的系统头文件和标准库
#include <assert.h>         // 断言功能
#include <cxxabi.h>         // C++名字修饰/解修饰
#include <execinfo.h>       // 调用栈追踪
#include <pthread.h>        // 线程相关
#include <stdint.h>         // 标准整数类型
#include <stdio.h>          // 标准输入输出
#include <string.h>         // 字符串操作
#include <sys/syscall.h>    // 系统调用
#include <sys/types.h>      // 系统类型定义
#include <unistd.h>         // POSIX系统接口
#include <iostream>         // 标准输入输出流
#include <sstream>          // 字符串流
#include <vector>           // 动态数组容器

namespace fiber  // 自定义命名空间，避免命名冲突
{
/**
 * @brief 获取当前线程ID
 * @return 线程ID（Linux系统下的tid）
 */
inline pid_t GetThreadId() {
    // 通过系统调用SYS_gettid获取线程ID
    return syscall(SYS_gettid);
}

/**
 * @brief 获取系统启动到当前的毫秒数
 * @return 毫秒数（单调递增，不受系统时间修改影响）
 */
static uint64_t GetElapsedMS() {
    struct timespec ts = {0};
    // 使用CLOCK_MONOTONIC_RAW时钟，提供原始单调时间，不受NTP调整影响
    clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
    // 秒转换为毫秒 + 纳秒转换为毫秒
    return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
}

/**
 * @brief 将C++修饰后的函数名解析为可读形式
 * @param str 被修饰的函数名字符串
 * @return 解析后的可读函数名
 */
static std::string demangle(const char *str) {
    size_t size = 0;
    int status = 0;
    std::string rt;
    rt.resize(256);  // 预分配字符串空间

    // 从符号中提取函数名部分（处理格式如"func(...)")
    if (1 == sscanf(str, "%*[^(]%*[^_]%255[^)+]", &rt[0])) {
        // 使用cxxabi库进行名字解修饰
        char *v = abi::__cxa_demangle(&rt[0], nullptr, &size, &status);
        if (v) {  // 解析成功
            std::string result(v);
            free(v);  // 释放动态分配的内存
            return result;
        }
    }

    // 解析失败时，尝试直接提取字符串
    if (1 == sscanf(str, "%255s", &rt[0])) {
        return rt;
    }

    // 所有尝试失败，返回原始字符串
    return str;
}

/**
 * @brief 获取当前线程的调用栈信息
 * @param bt 用于存储调用栈信息的vector
 * @param size 最大获取的栈帧数量
 * @param skip 跳过的栈帧数量（用于排除当前函数自身等）
 */
static void Backtrace(std::vector<std::string> &bt, int size, int skip) {
    // 分配存储栈帧地址的数组
    void **array = (void **)malloc((sizeof(void *) * size));
    // 获取实际的栈帧数量
    size_t s = ::backtrace(array, size);

    // 将栈帧地址转换为符号字符串（函数名+地址等）
    char **strings = backtrace_symbols(array, s);
    if (strings == NULL) {  // 转换失败处理
        std::cout << "backtrace_synbols error" << std::endl;
        return;
    }

    // 解析每个栈帧的符号并存储（跳过指定数量的栈帧）
    for (size_t i = skip; i < s; ++i) {
        bt.push_back(demangle(strings[i]));
    }

    // 释放动态分配的内存
    free(strings);
    free(array);
}

/**
 * @brief 将调用栈信息转换为字符串
 * @param size 最大获取的栈帧数量
 * @param skip 跳过的栈帧数量
 * @param prefix 每行栈信息前的前缀字符串
 * @return 包含调用栈信息的字符串
 */
static std::string BacktraceToString(int size, int skip, const std::string &prefix) {
    std::vector<std::string> bt;
    Backtrace(bt, size, skip);  // 获取调用栈

    // 将栈信息拼接为字符串
    std::stringstream ss;
    for (size_t i = 0; i < bt.size(); ++i) {
        ss << prefix << bt[i] << std::endl;
    }
    return ss.str();
}

/**
 * @brief 条件断言处理函数
 * @param condition 断言条件（为false时触发断言）
 * @param err 错误信息
 * @note 当条件不满足时，输出错误位置、信息和调用栈，然后触发assert
 */
static void CondPanic(bool condition, std::string err) {
    if (!condition) {  // 条件不满足时执行
        // 输出断言位置（文件名和行号）及错误信息
        std::cout << "[assert by] (" << __FILE__ << ":" << __LINE__ << "),err: " << err << std::endl;
        // 输出调用栈信息（跳过前3层无关栈帧）
        std::cout << "[backtrace]\n" << BacktraceToString(6, 3, "") << std::endl;
        // 触发标准断言（会终止程序）
        assert(condition);
    }
}

}  // namespace fiber

#endif  // __FIBER_UTIL_H__